package model;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;

import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import algo.DistributionResult;

import com.google.inject.BindingAnnotation;
import com.google.inject.Inject;


@BindingAnnotation
@Target({ FIELD, PARAMETER, METHOD })
@Retention(RUNTIME)
@interface StartCount {
};

public class MainModel {

	
	private List<ChangeListener> listeners = new ArrayList<>();
	
	private Map<DebateFormat, Integer> debateCounts;
	private DistributionResult result;
	
	public DistributionResult getResult() {
		return result;
	}

	public void setResult(DistributionResult result) {
		this.result = result;
		castChange(new ChangeEvent(this));
	}

	@Inject
	public MainModel(@StartCount int startCount, Set<DebateFormat> debateFormats) {
		this.debateCounts = new HashMap<>();
		for (DebateFormat format: debateFormats) {
			debateCounts.put(format, startCount);
		}
	}
	
	public int getDebateCount(DebateFormat format) {
		Integer debateCount = debateCounts.get(format);
		if (debateCount == null) {
			throw new NoSuchElementException("Unknown debate format");
		}
		return debateCount;
	}

	public void setDebateCount(DebateFormat format, int debateCount) {
		if (debateCount != getDebateCount(format)) {
			if (debateCount < 0) {
				throw new IllegalArgumentException("debateCount must be at least 0");
			}
			debateCounts.put(format, debateCount);
			castChange(new ChangeEvent(this));
		}
	}

	public void addChangeListener(ChangeListener changeListener) {
		listeners.add(changeListener);
	}

	public void removeChangeListener(ChangeListener changeListener) {
		listeners.remove(changeListener);
	}

	private void castChange(ChangeEvent e) {
		for (ChangeListener l : listeners) {
			l.stateChanged(e);
		}
	}

	public Map<DebateFormat, Integer> getSpeakerCounts() {
		return Collections.unmodifiableMap(debateCounts);
	}
}
